/* Copyright © 2015 Hein-Pieter van Braam <hp@tmm.cx>
 * This work is free. You can redistribute it and/or modify it under the
 * terms of the Do What The Fuck You Want To Public License, Version 2,
 * as published by Sam Hocevar. See the COPYING file for more details.
 *
 * Text copied from http://www.firthworks.com/roger/cloak/
*/

#include <iostream>
#include <vector>
#include <cstdlib>
#include <cstddef>

#include <readline/readline.h>
#include <readline/history.h>

#define BOLD    "\033[1m"
#define NO_BOLD "\033[22m"

using namespace std;

class game;

enum direction {
	north,
	east,
	south,
	west
};

class thing {
public:
	thing(string name, string description);
	virtual ~ thing();
	virtual string& name();
	virtual string& description();

	virtual bool can_examine();
	virtual string& examine();
private:
	string _name;
	string _description;
};

thing::thing(string name, string description):
	_name(name), _description(description) {
}

thing::~thing() {
}

string& thing::name() {
	return _name;
}

string& thing::description() {
	return _description;
}

bool thing::can_examine() {
	return true;
}

string& thing::examine() {
	return _description;
}

class room : public thing {
friend class game;
public:
	room(string name, string description);
	virtual ~room();
	virtual bool can_north();
	virtual room* north();
	virtual bool can_east();
	virtual room* east();
	virtual bool can_south();
	virtual room* south();
	virtual bool can_west();
	virtual room* west();
protected:
	room* _north;
	room* _east;
	room* _south;
	room* _west;
private:
	bool can_go(direction d);
};

room::room(string name, string description):
	thing(name, description) {
}

room::~room() {
}

bool room::can_go(direction d) {
	bool success;

	switch (d) {
		case direction::north: 
			success = _north ? true : false;
			break;
		case direction::east: 
			success = _east ? true : false;
			break;
		case direction::south: 
			success = _south ? true : false;
			break;
		case direction::west: 
			success = _west ? true : false;
			break;
	}

	if(! success)
		cout << "You can't go that way." << endl;

	return success;
}

bool room::can_north() {
	return can_go(direction::north);
}

room* room::north() {
	return _north;
}

bool room::can_east() {
	return can_go(direction::east);
}

room* room::east() {
	return _east;
}

bool room::can_south() {
	return can_go(direction::south);
}

room* room::south() {
	return _south;
}

bool room::can_west() {
	return can_go(direction::west);
}

room* room::west() {
	return _west;
}

class foyer : public room {
public:
	foyer();
	virtual ~foyer();

	bool can_north();
};

foyer::foyer():
	room("Foyer of the Opera House",
	"You are standing in a spacious hall, splendidly decorated in red and gold, with glittering chandeliers overhead.  The entrance from the street is to the north, and there are doorways south and west."
        ) {
}

foyer::~foyer() {
}

bool foyer::can_north() {
	cout << "You've only just arrived, and besides, the weather outside seems to be getting worse." << endl;
	return false;
}

class bar : public room {
public:
	bar();
	~bar();
};

bar::bar():
	room("Foyer Bar",
	"The bar, much rougher than you'd have guessed after the opulence of the foyer to the north, is completely empty.  There seems to be some sort of message scrawled in the sawdust on the floor."
	) {
}

bar::~bar() {
}

class cloakroom : public room {
public:
	cloakroom();
	~cloakroom();
};

cloakroom::cloakroom():
	room("The Cloakroom",
	"The walls of this small room were clearly once lined with hooks, though now only one remains.  The exit is a door to the east."
	) {
}

cloakroom::~cloakroom() {
}

class game {
public:
	game();
	~game();
	void parse(string input);
private:
	room* _room;
	vector<thing*> _things;
};

game::game() {
	room *f = new foyer;
	room *b = new bar;
	room *c = new cloakroom;

	f->_south = b;
	f->_west = c;
	b->_north = f;
	c->_east = f;

	_room = f;
	_things.push_back(f);
	_things.push_back(b);
	_things.push_back(c);
}

game::~game() {
	for (auto thing: _things) {
		delete thing;
	}
}

void game::parse(string input) {
	if (input == "look") {
		if (_room->can_examine()) 
			cout << _room->examine() << endl;
	} else if (input == "north") {
		if (_room->can_north()) 
			_room = _room->north();
	} else if (input == "east") {
		if (_room->can_east()) 
			_room = _room->east();
	} else if (input == "south") {
		if (_room->can_south()) 
			_room = _room->south();
	} else if (input == "west") {
		if (_room->can_west()) 
			_room = _room->west();
	} else {
		cout << "I don't know how to \"" << input << "\"" << endl;
	}
}

int main() {
	char *i;
	const char *prompt = "> ";

	cout << "Hurrying through the rainswept November night, you're glad to see the bright lights of the Opera House.  It's surprising that there aren't more people about but, hey, what do you expect in a cheap demo game...?" << endl;

	game game;

	for (;;) {
		cout << endl;

		i = readline(prompt);

		if (!i)
			break;

		add_history(i);
		game.parse(string(i));
		free(i);
	}

	cout << endl;
	return 0;
}
